package com.lagou.ipersistence.scripting.defaults;

import com.lagou.ipersistence.executor.parameter.ParameterHandler;
import com.lagou.ipersistence.mapping.BoundSql;
import com.lagou.ipersistence.mapping.MappedStatement;
import com.lagou.ipersistence.mapping.ParameterMapping;
import com.lagou.ipersistence.reflection.MetaObject;
import com.lagou.ipersistence.session.Configuration;
import com.lagou.ipersistence.type.JdbcType;
import com.lagou.ipersistence.type.TypeException;
import com.lagou.ipersistence.type.TypeHandler;
import com.lagou.ipersistence.type.TypeHandlerRegistry;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

/**
 * @author Yan Jiahong
 * Created on 2020/11/22
 */
public class DefaultParameterHandler implements ParameterHandler {
    private final TypeHandlerRegistry typeHandlerRegistry;
    private final MappedStatement mappedStatement;
    private final Object parameterObject;
    private final BoundSql boundSql;
    private final Configuration configuration;

    public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        this.mappedStatement = mappedStatement;
        this.configuration = mappedStatement.getConfiguration();
        this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
        this.parameterObject = parameterObject;
        this.boundSql = boundSql;
    }

    public Object getParameterObject() {
        return parameterObject;
    }

    public void setParameters(PreparedStatement ps) {
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        StringBuilder debugSb = new StringBuilder();
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                String propertyName = parameterMapping.getProperty();
                Object value;
                if (parameterObject == null) {
                    value = null;
                } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                    value = parameterObject;
                } else {
                    MetaObject metaObject = configuration.newMetaObject(parameterObject);
                    value = metaObject.getValue(propertyName);
                }
                debugSb.append(value).append("(").append(parameterMapping.getJavaType().getSimpleName()).append(")").append(", ");
                TypeHandler<Object> typeHandler = (TypeHandler<Object>) parameterMapping.getTypeHandler();
                JdbcType jdbcType = parameterMapping.getJdbcType();
                if (value == null && jdbcType == null) {
                    jdbcType = JdbcType.OTHER;
                }
                try {
                    typeHandler.setParameter(ps, i + 1, value, jdbcType);
                } catch (SQLException | TypeException e) {
                    throw new TypeException("无法为mapping: " + parameterMapping + "设置参数. 原因: " + e, e);
                }
            }
        }
        String sql = boundSql.getSql().replaceAll("[\n\t]","").trim();
        System.out.println("DEBUG ==> Preparing: " + sql);
        String parameters = debugSb.toString().trim();
        if (parameters.endsWith(",")) {
            parameters = parameters.substring(0, parameters.lastIndexOf(","));
        }
        System.out.println("DEBUG ==> Parameters: " + parameters);
    }
}